home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995 August: Tool Chest / Dev.CD Aug 95 TC / Dev.CD Aug 95 TC.toast / New System Software Extensions / QuickDraw™ GX 1.1.2 / Programming Stuff / QuickDraw™ GX Libraries / Graphics libraries / layout edit library.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-10  |  36.5 KB  |  1,739 lines  |  [TEXT/MPS ]

  1. /*
  2.     layout edit library.c
  3.     
  4.     Simple layout editing based on the TextEdit model.
  5.     
  6.     Copyright ®1992, 1994 Apple Computer, Inc. All rights reserved.
  7. */
  8.  
  9. #include <Types.h>
  10. #include <Memory.h>
  11. #include <Events.h>
  12. #include <OSUtils.h>
  13. #include <Scrap.h>
  14. #include <Script.h>
  15.  
  16. #include "selection library.h"
  17. #include "layout types.h"
  18. #include "layout routines.h"
  19. #include "graphics routines.h"
  20. #include "graphics libraries.h"
  21. #include "graphics toolbox.h"
  22. #include "storage library.h"
  23. #include "layout edit library.h"
  24.  
  25.  
  26. #define LockHandle(handle) (HLock ((Handle)handle), *handle)
  27. #define UnlockHandle(handle) HUnlock ((Handle)handle)
  28.  
  29. #define LockEditHandle(handle) (LayoutEditPtr) LockHandle(handle)
  30. #define UnlockEditHandle(handle) UnlockHandle(handle)
  31.  
  32. #define MIN(a,b) ((a) < (b)? (a): (b))
  33. #define MAX(a,b) ((a) > (b)? (a): (b))
  34.  
  35. #define maxRanges 10
  36. #define textBufferLength 16
  37. #define nextUpdateDelta 5
  38.  
  39. #define layoutOutOfDate 0x8000
  40. #define highlightOutOfDate 0x4000
  41. #define highlightBlinks 0x2000
  42. #define highlightIsBlinking 0x1000
  43.  
  44. #define BOUNDS 0
  45.  
  46. enum
  47. {
  48.     backSpace = 8,
  49.     leftArrow = 0x1C,
  50.     rightArrow,
  51.     upArrow,
  52.     downArrow
  53. };
  54.  
  55. typedef unsigned long ulong;
  56. typedef unsigned short ushort;
  57.  
  58. /*
  59.     The LayoutEditRecord contains the layout and highlight shapes,
  60.     the selection. flags contains flags which indicate that the
  61.     layout and highlight shapes haven't been rebuilt since their
  62.     corresponding data in the LayoutEditRecord has been changed.
  63.     
  64.     nextUpdate time, if non-zero tells the idle routine when to
  65.     update and re-draw the layout gxShape. 
  66.     
  67.     selectionRanges is working storage used for manipulating the
  68.     layout's selection. NOTE: the actual handle containing the
  69.     LayoutEditRecord will be large enough to contain the
  70.     SelectionOffsetRange array which immediately follows selectionRanges.
  71. */
  72. typedef struct {
  73.     short flags;
  74.     short highlightHideCount;
  75.     short    oldScript;
  76.     SelectionOffset synchOffset;
  77.     gxShape layout;
  78.     gxShape eraser;
  79.     gxShape highlight;
  80.  
  81. #if BOUNDS
  82.     gxShape bounds;
  83.     gxShape boundsEraser;
  84. #endif
  85.  
  86.     SelectionHandle selection;
  87.     gxShape scrap;
  88.     ulong nextUpdateTime;
  89.     ulong nextBlinkTime;
  90.     long deleteStartOffset;
  91.     long deleteEndOffset;
  92.     gxStyle insertionStyle;
  93.     short insertionLevel;
  94.     short textBufferOffset;
  95.     char textBuffer[textBufferLength];
  96.     SelectionRanges selectionRanges;
  97. } LayoutEditRecord, *LayoutEditPtr;
  98.  
  99.  
  100. /*
  101.     I N T E R N A L   R O U T I N E S
  102. */
  103.  
  104.  
  105. /*
  106.     Draw the part of the layout which has changed.
  107. */
  108. static void DrawDifference(LayoutEditPtr layout)
  109. {
  110.     GXDrawShape(layout->eraser);
  111.  
  112. #if BOUNDS
  113.     GXDrawShape(layout->boundsEraser);
  114. #endif
  115.  
  116.     GXDrawShape(layout->layout);
  117.  
  118. #if BOUNDS
  119.     GXDrawShape(layout->bounds);
  120. #endif
  121. }
  122.  
  123. /*
  124.     Synch the keyboard to the font at the new selection.
  125. */
  126. static void SynchKeyboard(LayoutEditPtr layout)
  127. {
  128.     long styleRuns;
  129.     gxStyle selectionStyle;
  130.     gxFontPlatform platform;
  131.     gxFontScript script;
  132.     gxFontLanguage language;
  133.  
  134.     GXGetLayoutParts(
  135.         layout->layout,
  136.         layout->synchOffset, layout->synchOffset,
  137.         nil,
  138.         &styleRuns, nil, &selectionStyle,
  139.         nil, nil, nil);
  140.     
  141.     if (styleRuns == 0 || selectionStyle == nil)
  142.         selectionStyle = GXGetShapeStyle(layout->layout);
  143.         
  144.     platform = GXGetStyleEncoding(selectionStyle, &script, &language);
  145.     
  146.     switch (platform)
  147.     {
  148.     case gxUnicodePlatform:
  149.         break;
  150.     
  151.     case gxMacintoshPlatform:
  152.         if (script == gxNoScript)
  153.             script = smRoman;
  154.         else
  155.             script -= 1;
  156.  
  157.         if (language != gxNoLanguage && GetScript((short) script, smScriptLang) != language - 1)
  158.             SetScript((short) script, smScriptLang, language - 1);
  159.         
  160.         if (GetEnvirons(smKeyScript) != script)    
  161.             KeyScript((short) script);
  162.         break;
  163.         
  164.     default:
  165.         break;
  166.     }
  167. }
  168.  
  169. /*
  170.     Make sure the caret is not blinked out.
  171. */
  172. static void ResetCaret(LayoutEditPtr layout)
  173. {
  174.     layout->nextBlinkTime = TickCount() + GetCaretTime();
  175.     if ((layout->flags & highlightBlinks) && (layout->flags & highlightIsBlinking))
  176.     {
  177.         layout->flags ^= highlightIsBlinking;
  178.         if (--layout->highlightHideCount == 0)
  179.             GXDrawShape(layout->highlight);
  180.     }
  181. }
  182.  
  183. /*
  184.     Build a selection from start to end. If start and end are equal,
  185.     the selection will be a caret.
  186. */
  187. static void NewSelection(LayoutEditPtr layout, SelectionOffset start, SelectionOffset end)
  188. {
  189.     layout->selectionRanges.rangeCount = 1;
  190.     layout->selectionRanges.ranges[0].minOffset = start;
  191.     layout->selectionRanges.ranges[0].maxOffset = end;
  192.     
  193.     if (layout->selection)
  194.         DisposeSelection(layout->selection);
  195.         
  196.     layout->selection = NewRangeSelection(&layout->selectionRanges.ranges[0]);
  197.     
  198.     layout->synchOffset = start;
  199.     layout->flags |= highlightOutOfDate;
  200. }
  201.  
  202. /*
  203.     Update the layout's highlight gxShape if the selection's
  204.     changed since we last built it.
  205. */
  206. static void UpdateHighlight(LayoutEditPtr layout)
  207. {
  208.     if (layout->flags & highlightOutOfDate)
  209.     {
  210.         DisposeShapeAt(&layout->highlight);
  211.         
  212.         layout->highlight = GetLayoutSelection(
  213.             layout->layout,
  214.             layout->selection,
  215.             0,
  216.             gxHighlightAverageAngle,
  217.             gxSplitCaretType);
  218.  
  219.         if (GetSelectionType(layout->selection) == simpleCaret)
  220.         {
  221.             SetShapeFastXorTransfer(layout->highlight, nil, nil);
  222.             layout->flags |= highlightBlinks;
  223.         }
  224.         else
  225.         {
  226.             SetShapeCommonTransfer(layout->highlight, gxHighlightMode);
  227.             SetShapeCommonColor(layout->highlight, gxWhite);
  228.  
  229.             layout->flags &= ~highlightBlinks;
  230.             if (layout->flags & highlightIsBlinking)
  231.             {
  232.                 layout->flags ^= highlightIsBlinking;
  233.                 --layout->highlightHideCount;
  234.             }
  235.         }
  236.             
  237.         DisposeStyleAt(&layout->insertionStyle);
  238.         layout->insertionLevel = -1;
  239.  
  240.         SynchKeyboard(layout);
  241.         layout->flags &= ~highlightOutOfDate;
  242.     }
  243. }
  244.  
  245. /*
  246.     Build a new selection from start to end, and a new highlight gxShape
  247.     that matches it.
  248. */
  249. static void NewSelectionAndHighlight(
  250.     LayoutEditPtr layout,
  251.     SelectionOffset start,
  252.     SelectionOffset end)
  253. {
  254.     NewSelection(layout, start, end);
  255.     UpdateHighlight(layout);
  256. }
  257.  
  258. /*
  259.     Return the offset of the glyph before the one at the specified
  260.     offset in the layout's text.
  261. */
  262. static SelectionOffset GetPreviousOffset(gxShape layout, SelectionOffset offset)
  263. {
  264.     ushort firstGlyph, secondGlyph;
  265.     gxLayoutOffsetState offsetState;
  266.     static SelectionOffset offsetStateSizes[] = {1, 1, 2, 2, 0};
  267.     
  268.     GXGetOffsetGlyphs(layout, offset, 0, &offsetState, &firstGlyph, &secondGlyph);
  269.     
  270.     return offset - offsetStateSizes[offsetState & ~gxOffsetInsideLigature];
  271. }
  272.  
  273. /*
  274.     Delete the text from the layout in the range specified by pRange.
  275. */
  276. static void DeleteRange(LayoutEditPtr layout, SelectionOffsetRange *pRange)
  277. {
  278.     if (layout->deleteStartOffset < 0)
  279.         layout->deleteEndOffset = pRange->maxOffset;
  280.         
  281.     layout->deleteStartOffset = pRange->minOffset;
  282.     layout->flags |= layoutOutOfDate;
  283. }
  284.  
  285.  
  286. /*
  287.     Delete the selected text from the layout. If the selection is a
  288.     caret, delete the character before the caret. Change the selection
  289.     to a caret just before the old selection.
  290. */
  291.  
  292. static void DeleteSelection(LayoutEditPtr layout)
  293. {
  294.     SelectionType selectionType = GetSelectionType(layout->selection);
  295.     SelectionOffset newCaret;
  296.  
  297.     switch (selectionType)
  298.     {
  299.     case emptySelection:
  300.         newCaret = 0;
  301.         break;
  302.     
  303.     case simpleCaret:
  304.     {
  305.         SelectionOffset caret = GetCaretSelection(layout->selection, nil);
  306.     
  307.         if(layout->textBufferOffset)
  308.         {
  309.             layout->textBufferOffset -= 1;
  310.             newCaret = caret - 1;
  311.         }
  312.         else if (caret > 0)
  313.         {
  314.             SelectionOffsetRange range;
  315.             SelectionOffset previous = GetPreviousOffset(layout->layout, caret);
  316.         
  317.             range.minOffset = newCaret = previous;
  318.             range.maxOffset = caret;
  319.             DeleteRange(layout, &range);
  320.         }
  321.         else newCaret = caret;
  322.         
  323.     break;
  324.     }
  325.     
  326.     case simpleRange:
  327.     case discontiguousRange:
  328.     {
  329.         long rangeCount;
  330.         SelectionRanges *ranges = &layout->selectionRanges;
  331.         SelectionOffsetRange *pRange;
  332.         
  333.         (void) GetRangeSelection(layout->selection, ranges);
  334.         rangeCount = ranges->rangeCount;
  335.         pRange = &ranges->ranges[rangeCount];
  336.         
  337.         /*
  338.             go through the ranges backwards to save sliding stuff
  339.             that'll get deleted later and so that the caret is set
  340.             for the first range.
  341.         */
  342.         while (--rangeCount >= 0)
  343.         {
  344.             DeleteRange(layout, --pRange);
  345.             newCaret = pRange->minOffset;
  346.         }
  347.             
  348.         break;
  349.     }
  350.     }
  351.     
  352.     /* set layout's selection to a caret before the deletion */
  353.     NewSelection(layout, newCaret, newCaret);
  354.     ResetCaret(layout);
  355. }
  356.  
  357. /*
  358.     Make sure the handle is at least newSize bytes long;
  359.     If it isn't, grow it to be newSize + extra.
  360. */
  361. static Ptr GrowAndLockHandle(Handle handle, Size newSize, Size extra)
  362. {
  363.     Size oldSize = GetHandleSize(handle);
  364.  
  365.     if (oldSize < newSize)
  366.         SetHandleSize(handle, newSize + extra);
  367.         
  368.     return LockHandle(handle);
  369. }
  370.  
  371. #if BOUNDS
  372. static void SetBounds(LayoutEditPtr layout)
  373. {
  374.     gxRectangle bounds;
  375.     
  376.     GXGetShapeTypographicBounds(layout->layout, &bounds);
  377.     GXSetRectangle(layout->bounds, &bounds);
  378.     GXIgnoreGraphicsNotice(transform_already_set);
  379.     GXSetShapeTransform(layout->bounds, GXGetShapeTransform(layout->layout));
  380.     GXPopGraphicsNotice();
  381. }
  382. #endif
  383.  
  384. static void SetEraser(LayoutEditPtr layout)
  385. {
  386.     layout->eraser = GXCopyToShape(layout->eraser, layout->layout);
  387.     SetShapeCommonColor(layout->eraser, gxWhite);
  388.  
  389. #if BOUNDS    
  390.     layout->boundsEraser = GXCopyToShape(layout->boundsEraser, layout->bounds);
  391.     SetShapeCommonColor(layout->boundsEraser, gxWhite);
  392. #endif
  393. }
  394.  
  395. /*
  396.     If the backing store in the LayoutEditRecord has changed since
  397.     the layout gxShape was last built, rebuild the layout.
  398. */
  399. static void UpdateLayout(LayoutEditPtr layout)
  400. {
  401.     if (layout->flags & layoutOutOfDate)
  402.     {
  403.         void *textBuffer = &layout->textBuffer, **text = nil;
  404.         short *levels = nil, levelRunCount = 0, styleRunCount = 0, textRunCount = 0,
  405.                     *textRunLength = nil, *styleRunLength = nil, *levelRunLength = nil;
  406.         gxStyle *styles = nil;
  407.         
  408.         SetEraser(layout);
  409.         
  410.         if (layout->textBufferOffset)
  411.         {
  412.             text = &textBuffer;
  413.             textRunLength = &layout->textBufferOffset;
  414.             textRunCount = 1;
  415.             
  416.             if (layout->insertionStyle)
  417.             {
  418.                 styles = &layout->insertionStyle;
  419.                 styleRunLength = textRunLength;
  420.                 styleRunCount = 1;
  421.             }
  422.             
  423.             if (layout->insertionLevel >= 0)
  424.             {
  425.                 levels = &layout->insertionLevel;
  426.                 levelRunLength = textRunLength;
  427.                 levelRunCount = 1;
  428.             }
  429.         }
  430.         
  431.         /* edit the layout */ 
  432.         GXSetLayoutParts(
  433.             layout->layout,
  434.             layout->deleteStartOffset,
  435.             layout->deleteEndOffset,
  436.             textRunCount,
  437.             textRunLength,
  438.             (const void **) text,
  439.             styleRunCount,
  440.             styleRunLength,
  441.             styles,
  442.             levelRunCount,
  443.             levelRunLength,
  444.             levels);
  445.  
  446. #if BOUNDS        
  447.         SetBounds(layout);
  448. #endif
  449.             
  450.         /* erase the old layout and draw the new one */
  451.         DrawDifference(layout);
  452.  
  453.         layout->flags &= ~layoutOutOfDate;
  454.         layout->nextUpdateTime = 0;
  455.         layout->textBufferOffset = 0;
  456.         layout->deleteStartOffset = -1;
  457.         layout->insertionLevel = -1;
  458.         DisposeStyleAt(&layout->insertionStyle);
  459.     }
  460. }
  461.  
  462. /*
  463.     Add a character to the layout at the selection. This routine
  464.     assumes that the selection is a caret; i.e. if it was a range,
  465.     the range has been deleted leaving a caret.
  466. */
  467. static void InsertByte(LayoutEditPtr layout, char byte)
  468. {
  469.     SelectionOffset caret;
  470.  
  471.     caret = layout->selectionRanges.ranges[0].minOffset;
  472.     
  473.     if (layout->textBufferOffset >= textBufferLength)
  474.         UpdateLayout(layout);
  475.     
  476.     if (layout->deleteStartOffset < 0)
  477.         layout->deleteStartOffset = layout->deleteEndOffset = caret;
  478.         
  479.     layout->textBuffer[layout->textBufferOffset++] = byte;
  480.     
  481.     /* set selection to a caret after the new byte */
  482.     NewSelection(layout, caret + 1, caret + 1);
  483.     ResetCaret(layout);
  484.     
  485.     layout->flags |= layoutOutOfDate;
  486. }
  487.  
  488. /*
  489.     If the highlight gxShape isn't already hidden, erase
  490.     it by drawing it on top of itself.
  491. */
  492. static void HideHighlight(LayoutEditPtr layout)
  493. {
  494.     if (layout->highlightHideCount++ == 0)
  495.         GXDrawShape(layout->highlight);
  496. }
  497.  
  498. /*
  499.     If the highlight gxShape isn't already visible, update it
  500.     and draw it.
  501. */
  502. static void ShowHighlight(LayoutEditPtr layout)
  503. {
  504.     if (--layout->highlightHideCount <= 0)
  505.     {
  506.         UpdateHighlight(layout);
  507.         GXDrawShape(layout->highlight);
  508.         layout->highlightHideCount = 0;
  509.     }
  510. }
  511.  
  512. /*
  513.     Draw the highlight shape (if it's visible).
  514. */
  515. static void DrawHighlight(LayoutEditPtr layout)
  516. {
  517.     if (layout->highlightHideCount <= 0)
  518.         GXDrawShape(layout->highlight);
  519. }
  520.  
  521. static void DrawChangedLayout(LayoutEditPtr layout)
  522. {
  523.     gxRectangle rect;
  524.     
  525.     HideHighlight(layout);
  526.  
  527. #if BOUNDS    
  528.     SetBounds(layout);
  529. #endif
  530.         
  531.     DrawDifference(layout);
  532.     
  533.     layout->flags |= highlightOutOfDate;
  534.     ShowHighlight(layout);
  535. }
  536.  
  537. static void CopySelection(LayoutEditPtr layout)
  538. {
  539.     SelectionType selectionType = GetSelectionType(layout->selection);
  540.  
  541.     switch (selectionType)
  542.     {
  543.     case emptySelection:
  544.     case simpleCaret:
  545.     case discontiguousRange:
  546.         break;
  547.     
  548.     case simpleRange:
  549.     {
  550.         SelectionRanges *ranges = &layout->selectionRanges;
  551.         SelectionOffsetRange *pRange;
  552.         
  553.         (void) GetRangeSelection(layout->selection, ranges);
  554.         pRange = ranges->ranges;
  555.  
  556.         layout->scrap = GXGetLayoutShapeParts(layout->layout, pRange->minOffset, pRange->maxOffset, layout->scrap);                
  557.  
  558.         break;
  559.     }
  560.     }
  561. }
  562.  
  563. static void PasteSelection(LayoutEditPtr layout)
  564. {
  565.     SelectionType selectionType = GetSelectionType(layout->selection);
  566.     SelectionOffset newCaret, startOffset, endOffset;
  567.     
  568.     SetEraser(layout);
  569.  
  570.     switch (selectionType)
  571.     {
  572.     case emptySelection:
  573.     case discontiguousRange:
  574.         return;
  575.  
  576.     case simpleCaret:
  577.         newCaret = startOffset = endOffset = GetCaretSelection(layout->selection, nil);
  578.         break;
  579.     
  580.     case simpleRange:
  581.     {
  582.         SelectionRanges *ranges = &layout->selectionRanges;
  583.         
  584.         (void) GetRangeSelection(layout->selection, ranges);
  585.         startOffset = ranges->ranges[0].minOffset;
  586.         endOffset = ranges->ranges[0].maxOffset;
  587.         newCaret = startOffset;
  588.         
  589.         
  590.         break;
  591.     }
  592.     }
  593.  
  594.     newCaret += GXGetLayout(layout->scrap, nil, 0, nil, nil, 0, nil, nil, nil, nil);
  595.     GXSetLayoutShapeParts(layout->layout, startOffset, endOffset, layout->scrap);
  596.  
  597. #if BOUNDS
  598.     SetBounds(layout);
  599. #endif
  600.  
  601.     DrawDifference(layout);
  602.     NewSelection(layout, newCaret, newCaret);
  603. }
  604.  
  605. static void AdjustSelectedLevels(LayoutEditPtr layout, short levelAdjust)
  606. {
  607.     short *lengths, *levels;
  608.     long levelRunCount;
  609.     SelectionType selectionType = GetSelectionType(layout->selection);
  610.     SelectionRanges *ranges = &layout->selectionRanges;
  611.     SelectionOffset startOffset, endOffset;
  612.     
  613.     UpdateLayout(layout);
  614.     
  615.     switch (selectionType)
  616.     {
  617.     case emptySelection:
  618.     case discontiguousRange:
  619.         return;
  620.         
  621.     case simpleCaret:
  622.         startOffset = endOffset = GetCaretSelection(layout->selection, nil);
  623.         break;
  624.     
  625.     case simpleRange:
  626.     {
  627.         SelectionRanges *ranges = &layout->selectionRanges;
  628.     
  629.         GetRangeSelection(layout->selection, ranges);
  630.         startOffset = ranges->ranges[0].minOffset;
  631.         endOffset = ranges->ranges[0].maxOffset;
  632.     }
  633.     break;
  634.     }
  635.     
  636.     GXGetLayoutParts(layout->layout, startOffset, endOffset, nil, nil, nil, nil, &levelRunCount, nil, nil);
  637.     
  638.     levels = (short *) NewPtr(levelRunCount * sizeof(short));
  639.     lengths = (short *) NewPtr(levelRunCount * sizeof(short));
  640.     
  641.     GXGetLayoutParts(layout->layout, startOffset, endOffset, nil, nil, nil, nil, nil, lengths, levels);
  642.     
  643.     if (startOffset == endOffset) layout->insertionLevel = MAX(*levels + levelAdjust, 0);
  644.     else
  645.     {
  646.         short i, length = endOffset - startOffset, *pl;
  647.     
  648.         SetEraser(layout);
  649.         
  650.         for (pl = levels, i = levelRunCount - 1; i >= 0; --i, ++pl)
  651.             *pl = MAX(*pl + levelAdjust, 0);
  652.  
  653.         
  654.         GXSetLayoutParts(
  655.             layout->layout,
  656.             startOffset,
  657.             endOffset,
  658.             0,
  659.             nil,
  660.             nil,
  661.             0,
  662.             nil,
  663.             nil,
  664.             levelRunCount,
  665.             lengths,
  666.             levels);
  667.             
  668.         HideHighlight(layout);
  669.  
  670.     #if BOUNDS
  671.         SetBounds(layout);
  672.     #endif
  673.  
  674.         DrawDifference(layout);
  675.         ShowHighlight(layout);
  676.         
  677.         layout->insertionLevel = -1;
  678.     }
  679.     
  680.     DisposePtr((Ptr) lengths);
  681.     DisposePtr((Ptr) levels);
  682. }
  683.  
  684.  
  685. /*
  686.     P U B L I C   R O U T I N E S
  687. */
  688.  
  689. LayoutEditHandle LayoutEditHandleFromLayout(gxShape layoutShape)
  690. {
  691.     LayoutEditHandle handle;
  692.     LayoutEditPtr layout;
  693. #if BOUNDS
  694.     gxRectangle bounds;
  695. #endif
  696.  
  697.     /* SetShapeFastXorTransfer(layoutShape, nil, nil); */
  698.     
  699.     handle = (LayoutEditHandle) NewHandle(
  700.         sizeof(LayoutEditRecord) + maxRanges * sizeof(SelectionOffsetRange));
  701.     
  702.     layout = LockEditHandle(handle);
  703.     layout->layout = layoutShape;
  704.     layout->eraser = nil;
  705.     layout->flags = 0;
  706.     layout->selection = nil;
  707.     layout->highlight = nil;
  708.     layout->scrap = nil;
  709.     layout->highlightHideCount = 0;
  710.     layout->nextUpdateTime = 0;
  711.     layout->nextBlinkTime = 0;
  712.     layout->textBufferOffset = 0;
  713.     layout->insertionStyle = nil;
  714.     layout->insertionLevel = -1;
  715.     layout->deleteStartOffset = -1;
  716.  
  717. #if BOUNDS    
  718.     layout->boundsEraser = nil;
  719.     GXGetShapeTypographicBounds(layoutShape, &bounds);
  720.     layout->bounds = GXNewRectangle(&bounds);
  721.     GXSetShapeFill(layout->bounds, gxClosedFrameFill);
  722. #endif
  723.     
  724.     /* set the initial selection to a caret before the first character */
  725.     NewSelectionAndHighlight(layout, 0, 0);
  726.         
  727.     UnlockHandle(handle);
  728.     
  729.     return handle;
  730. }
  731.  
  732. LayoutEditHandle NewLayoutEditHandle(
  733.     long textRunCount,
  734.     const short textRunLengths[],
  735.     const void *text[],
  736.     long styleRunCount,
  737.     const short styleRunLengths[],
  738.     const gxStyle styles[],
  739.     long levelRunCount,
  740.     const short levelRunLengths[],
  741.     const short levels[],
  742.     gxLayoutOptions *layoutOptions,
  743.     gxPoint *position,
  744.     gxStyle defaultStyle)
  745. {
  746.     gxShape layoutShape;
  747.     
  748.     /* just call GXNewLayout for param error checking */
  749.     layoutShape = GXNewLayout(
  750.         textRunCount,
  751.         textRunLengths,
  752.         text,
  753.         styleRunCount,
  754.         styleRunLengths,
  755.         styles,
  756.         levelRunCount,
  757.         levelRunLengths,
  758.         levels,
  759.         layoutOptions,
  760.         position);
  761.     
  762.     /* If GXNewLayout posts an error, we won't get here... */
  763.  
  764.     if (defaultStyle) GXSetShapeStyle(layoutShape, defaultStyle);
  765.     return LayoutEditHandleFromLayout(layoutShape);
  766. }
  767.  
  768. long GetLayoutEditHandle(
  769.     LayoutEditHandle handle,
  770.     void *text,
  771.     long *styleRunCount,
  772.     short styleRunLengths[],
  773.     gxStyle styles[],
  774.     long *levelRunCount,
  775.     short levelRunLengths[],
  776.     short levels[],
  777.     gxLayoutOptions *layoutOptions,
  778.     gxPoint *position)
  779. {
  780.     LayoutEditPtr layout = LockEditHandle(handle);
  781.     long result;
  782.     
  783.     UpdateLayout(layout);
  784.     
  785.     result = GXGetLayout(
  786.         layout->layout,
  787.         text,
  788.         styleRunCount,
  789.         styleRunLengths,
  790.         styles,
  791.         levelRunCount,
  792.         levelRunLengths,
  793.         levels,
  794.         layoutOptions,
  795.         position);
  796.     
  797.     UnlockHandle(handle);
  798.     
  799.     return result;
  800. }
  801.  
  802. void SetLayoutEditHandle(
  803.     LayoutEditHandle handle,
  804.     long textRunCount,
  805.     const short textRunLengths[],
  806.     const void *text[],
  807.     long styleRunCount,
  808.     const short styleRunLengths[],
  809.     const gxStyle styles[],
  810.     long levelRunCount,
  811.     const short levelRunLengths[],
  812.     const short levels[],
  813.     const gxLayoutOptions *layoutOptions,
  814.     const gxPoint *position)
  815. {
  816.     LayoutEditPtr layout = LockEditHandle(handle);
  817.     
  818.     SetEraser(layout);
  819.  
  820.     UpdateLayout(layout);
  821.     
  822.     GXSetLayout(
  823.         layout->layout,
  824.         textRunCount,
  825.         textRunLengths,
  826.         text,
  827.         styleRunCount,
  828.         styleRunLengths,
  829.         styles,
  830.         levelRunCount,
  831.         levelRunLengths,
  832.         levels,
  833.         layoutOptions,
  834.         position);
  835.     
  836.     DrawChangedLayout(layout);
  837.     
  838.     UnlockHandle(handle);
  839. }
  840.  
  841. void SetLayoutEditHandleParts(
  842.     LayoutEditHandle handle,
  843.     gxByteOffset oldStartOffset,
  844.     gxByteOffset oldEndOffset,
  845.     long newTextRunCount,
  846.     const short newTextRunLengths[],
  847.     const void *newText[],
  848.     long newStyleRunCount,
  849.     const short newStyleRunLengths[],
  850.     const gxStyle newStyles[],
  851.     long newLevelRunCount,
  852.     const short newLevelRunLengths[],
  853.     const short newLevels[])
  854. {
  855.     LayoutEditPtr layout = LockEditHandle(handle);
  856.     
  857.     SetEraser(layout);
  858.  
  859.     UpdateLayout(layout);
  860.     
  861.     GXSetLayoutParts(
  862.         layout->layout,
  863.         oldStartOffset,
  864.         oldEndOffset,
  865.         newTextRunCount,
  866.         newTextRunLengths,
  867.         newText,
  868.         newStyleRunCount,
  869.         newStyleRunLengths,
  870.         newStyles,
  871.         newLevelRunCount,
  872.         newLevelRunLengths,
  873.         newLevels);
  874.     
  875.     DrawChangedLayout(layout);
  876.     
  877.     UnlockHandle(handle);
  878. }
  879.  
  880. void SetLayoutEditHandleSelectedParts(
  881.     LayoutEditHandle handle,
  882.     long newTextRunCount,
  883.     const short newTextRunLengths[],
  884.     const void *newText[],
  885.     long newStyleRunCount,
  886.     const short newStyleRunLengths[],
  887.     const gxStyle newStyles[],
  888.     long newLevelRunCount,
  889.     const short newLevelRunLengths[],
  890.     const short newLevels[])
  891. {
  892.     LayoutEditPtr layout;
  893.     SelectionOffset startOffset, endOffset;
  894.     
  895.     layout = LockEditHandle(handle);
  896.     UpdateLayout(layout);
  897.     
  898.     DisposeStyleAt(&layout->insertionStyle);
  899.     layout->insertionLevel = -1;
  900.                     
  901.     switch (GetSelectionType(layout->selection))
  902.     {
  903.     case emptySelection:
  904.     case discontiguousRange:
  905.         /* should never happen */
  906.         break;
  907.         
  908.     case simpleCaret:
  909.         startOffset = endOffset = GetCaretSelection(layout->selection, nil);
  910.  
  911.         if (newTextRunCount == 0)
  912.         {
  913.             if (newStyleRunCount == 1 && newStyleRunLengths[0] == 0)
  914.             {
  915.                 layout->insertionStyle = GXCloneStyle(newStyles[0]);
  916.                 newStyleRunCount = 0;
  917.                 newStyleRunLengths = nil;
  918.                 newStyles = nil;
  919.             }
  920.             
  921.             if (newLevelRunCount == 1 && newLevelRunLengths[0] == 0)
  922.             {
  923.                 layout->insertionLevel = newLevels[0];
  924.                 newLevelRunCount = 0;
  925.                 newLevelRunLengths = nil;
  926.                 newLevels = nil;
  927.             }
  928.         }
  929.             
  930.         break;
  931.         
  932.     case simpleRange:
  933.     {
  934.         SelectionRanges *ranges = &layout->selectionRanges;
  935.     
  936.         (void) GetRangeSelection(layout->selection, ranges);
  937.         
  938.         startOffset = ranges->ranges[0].minOffset;
  939.         endOffset = ranges->ranges[0].maxOffset;
  940.         
  941.         break;
  942.     }
  943.     }
  944.  
  945.         
  946.     if (newTextRunCount > 0 || newStyleRunCount > 0 || newLevelRunCount > 0)
  947.     {
  948.         SetEraser(layout);
  949.     
  950.         GXSetLayoutParts(
  951.             layout->layout,
  952.             startOffset,
  953.             endOffset,
  954.             newTextRunCount, newTextRunLengths, newText,
  955.             newStyleRunCount, newStyleRunLengths, newStyles,
  956.             newLevelRunCount, newLevelRunLengths, newLevels);
  957.  
  958.         DrawChangedLayout(layout);
  959.     }
  960.         
  961.     UnlockEditHandle(handle);
  962. }
  963.  
  964. void SetLayoutEditHandleShapeParts(
  965.     LayoutEditHandle handle,
  966.     gxByteOffset startOffset,
  967.     gxByteOffset endOffset,
  968.     gxShape insert)
  969. {
  970.     LayoutEditPtr layout = LockEditHandle(handle);
  971.     
  972.     SetEraser(layout);
  973.  
  974.     UpdateLayout(layout);
  975.     
  976.     GXSetLayoutShapeParts(
  977.         layout->layout,
  978.         startOffset,
  979.         endOffset,
  980.         insert);
  981.     
  982.     DrawChangedLayout(layout);
  983.     
  984.     UnlockHandle(handle);
  985. }
  986.  
  987. long GetLayoutEditHandleParts(
  988.     LayoutEditHandle handle,
  989.     gxByteOffset startOffset,
  990.     gxByteOffset endOffset,
  991.     void *text,
  992.     long *styleRunCount,
  993.     short styleRunLengths[],
  994.     gxStyle styles[],
  995.     long *levelRunCount,
  996.     short levelRunLengths[],
  997.     short levels[])
  998. {
  999.     LayoutEditPtr layout = LockEditHandle(handle);
  1000.     long result;
  1001.     
  1002.     UpdateLayout(layout);
  1003.     
  1004.     result = GXGetLayoutParts(
  1005.         layout->layout,
  1006.         startOffset,
  1007.         endOffset,
  1008.         text,
  1009.         styleRunCount,
  1010.         styleRunLengths,
  1011.         styles,
  1012.         levelRunCount,
  1013.         levelRunLengths,
  1014.         levels);
  1015.     
  1016.     UnlockHandle(handle);
  1017.     return result;
  1018. }
  1019.  
  1020. long GetLayoutEditHandleSelectedParts(
  1021.     LayoutEditHandle handle,
  1022.     void *text,
  1023.     long *styleRunCount,
  1024.     short styleRunLengths[],
  1025.     gxStyle styles[],
  1026.     long *levelRunCount,
  1027.     short levelRunLengths[],
  1028.     short levels[])
  1029. {
  1030.     SelectionType selectionType;
  1031.     gxByteOffset endOffset, startOffset;
  1032.     LayoutEditPtr layout;
  1033.     long result;
  1034.     
  1035.     layout = LockEditHandle(handle);
  1036.     UpdateLayout(layout);
  1037.     selectionType = GetSelectionType(layout->selection);
  1038.     
  1039.     switch (selectionType)
  1040.     {
  1041.     case emptySelection:
  1042.     case discontiguousRange:
  1043.         /* should never happen */
  1044.         break;
  1045.         
  1046.     case simpleCaret:
  1047.     
  1048.         startOffset = endOffset = GetCaretSelection(layout->selection, nil);
  1049.  
  1050.         if (styles != nil && layout->insertionStyle != nil)
  1051.         {
  1052.             *styles = layout->insertionStyle;
  1053.             styles = nil;
  1054.         }
  1055.         
  1056.         if (levels != nil && layout->insertionLevel >= 0)
  1057.         {
  1058.             *levels = layout->insertionLevel;
  1059.             levels = nil;
  1060.         }
  1061.  
  1062.         break;
  1063.         
  1064.     case simpleRange:
  1065.     {
  1066.         SelectionRanges *ranges = &layout->selectionRanges;
  1067.         short length;
  1068.                 
  1069.         (void) GetRangeSelection(layout->selection, ranges);
  1070.         
  1071.         startOffset = ranges->ranges[0].minOffset;
  1072.         endOffset = ranges->ranges[0].maxOffset;
  1073.     }
  1074.     }
  1075.             
  1076.     result = GXGetLayoutParts(
  1077.         layout->layout,
  1078.         startOffset,
  1079.         endOffset,
  1080.         text,
  1081.         styleRunCount,
  1082.         styleRunLengths,
  1083.         styles,
  1084.         levelRunCount,
  1085.         levelRunLengths,
  1086.         levels);
  1087.     
  1088.     UnlockHandle(handle);
  1089.     return result;
  1090. }
  1091.  
  1092. gxShape GetLayoutEditHandleShapeParts(
  1093.     LayoutEditHandle handle,
  1094.     gxByteOffset startOffset,
  1095.     gxByteOffset endOffset,
  1096.     gxShape dest)
  1097. {
  1098.     LayoutEditPtr layout = LockEditHandle(handle);
  1099.     gxShape result;
  1100.     
  1101.     UpdateLayout(layout);
  1102.     
  1103.     result = GXGetLayoutShapeParts(layout->layout, startOffset, endOffset, dest);
  1104.     
  1105.     UnlockHandle(handle);
  1106.     return result;
  1107. }
  1108.  
  1109. void LayoutEditRotateShape(LayoutEditHandle handle, Fixed degrees, Fixed translateX, Fixed translateY)
  1110. {
  1111.     LayoutEditPtr layout;
  1112.     
  1113.     layout = LockEditHandle(handle);
  1114.     
  1115.     UpdateLayout(layout);
  1116.  
  1117.     SetEraser(layout);
  1118.     
  1119.     GXRotateShape(layout->layout, degrees, translateX, translateY);
  1120.     
  1121.     DrawChangedLayout(layout);
  1122.     
  1123.     UnlockEditHandle(handle);
  1124. }
  1125.  
  1126. void LayoutEditIdle(LayoutEditHandle handle)
  1127. {
  1128.     ulong ticks = TickCount();
  1129.     ulong nextUpdateTime = ((LayoutEditPtr) *handle)->nextUpdateTime;
  1130.     ulong nextBlinkTime = ((LayoutEditPtr) *handle)->nextBlinkTime;
  1131.     
  1132.     if ((nextUpdateTime != 0) && (ticks >= nextUpdateTime))
  1133.     {
  1134.         LayoutEditPtr layout = LockEditHandle(handle);
  1135.         
  1136.         HideHighlight(layout);
  1137.         UpdateLayout(layout);
  1138.         ShowHighlight(layout);
  1139.         
  1140.         UnlockEditHandle(handle);
  1141.     }
  1142.  
  1143.     if (((LayoutEditPtr) *handle)->flags & highlightBlinks)
  1144.     {
  1145.         if (ticks >= nextBlinkTime)
  1146.         {
  1147.             LayoutEditPtr layout = LockEditHandle(handle);
  1148.  
  1149.             if (layout->flags & highlightIsBlinking)
  1150.             {
  1151.                 UpdateLayout(layout);
  1152.                 ShowHighlight(layout);
  1153.             }
  1154.             else
  1155.             {
  1156.                 HideHighlight(layout);
  1157.             }
  1158.             
  1159.             layout->flags ^= highlightIsBlinking;
  1160.  
  1161.             layout->nextBlinkTime = ticks + GetCaretTime();
  1162.  
  1163.             UnlockEditHandle(handle);
  1164.         }
  1165.     }
  1166. }
  1167.  
  1168. void LayoutEditClick(LayoutEditHandle handle, gxPoint hitDown, boolean extend)
  1169. {
  1170.     LayoutEditPtr layout = LockEditHandle(handle); 
  1171.     gxPoint lastPoint = hitDown;
  1172.     SelectionOffset firstHitOffset, lastHitOffset;
  1173.     gxLayoutHitInfo hitInfo;
  1174.     boolean oldIsCaret, newIsCaret = true;
  1175.     gxShape diffHighlight = nil, oldHighlight = nil;
  1176.     gxViewPort layoutViewPort = GetShapeViewPort(layout->layout);
  1177.  
  1178.     /* get the offset for the hit down gxPoint */
  1179.     GXHitTestLayout(layout->layout, &hitDown, gxHighlightAverageAngle, &hitInfo, nil);
  1180.  
  1181.     if (extend)
  1182.     {
  1183.         boolean extendLeft;
  1184.         SelectionOffset oldFirstOffset, oldLastOffset;
  1185.         
  1186.         switch (GetSelectionType(layout->selection))
  1187.         {
  1188.         case emptySelection:
  1189.         case discontiguousRange:
  1190.             oldFirstOffset = oldLastOffset = (SelectionOffset) hitInfo.hitSideOffset;
  1191.             break;
  1192.             
  1193.         case simpleCaret:
  1194.             oldFirstOffset = oldLastOffset = GetCaretSelection(layout->selection, nil);
  1195.             break;
  1196.         
  1197.         case simpleRange:
  1198.         {
  1199.             SelectionRanges *ranges = &layout->selectionRanges;
  1200.         
  1201.             (void) GetRangeSelection(layout->selection, ranges);
  1202.             oldFirstOffset = ranges->ranges[0].minOffset;
  1203.             oldLastOffset = ranges->ranges[0].maxOffset;
  1204.             break;
  1205.         }
  1206.         }
  1207.  
  1208.         if (hitInfo.hitSideOffset <= oldFirstOffset)
  1209.             extendLeft = true;
  1210.         else if (hitInfo.hitSideOffset >= oldLastOffset)
  1211.             extendLeft = false;
  1212.         else
  1213.             extendLeft = ((hitInfo.hitSideOffset - oldFirstOffset) <= (oldLastOffset - hitInfo.hitSideOffset));
  1214.  
  1215.         if (extendLeft)
  1216.         {
  1217.             firstHitOffset = (SelectionOffset) hitInfo.hitSideOffset;
  1218.             lastHitOffset = oldLastOffset;
  1219.         }
  1220.         else
  1221.         {
  1222.             firstHitOffset = oldFirstOffset;
  1223.             lastHitOffset = (SelectionOffset) hitInfo.hitSideOffset;
  1224.         }
  1225.     }
  1226.     else
  1227.         firstHitOffset = lastHitOffset = (SelectionOffset) hitInfo.hitSideOffset;
  1228.     
  1229.     /* erase the old highlight */
  1230.     ResetCaret(layout);
  1231.     DrawHighlight(layout);
  1232.  
  1233.     /* recompute the selection and highlight while the mouse button is still down */
  1234.     while (Button())
  1235.     {
  1236.         GXGetViewPortMouse(layoutViewPort, &hitDown);
  1237.     
  1238.         /* continue if the mouse hasn't moved */
  1239.         if (hitDown.x == lastPoint.x && hitDown.y == lastPoint.y)
  1240.             continue;
  1241.         
  1242.         lastPoint = hitDown;
  1243.         GXHitTestLayout(layout->layout, &hitDown, gxHighlightAverageAngle, &hitInfo, nil);
  1244.         
  1245.         /* continue if the selection hasn't changed */
  1246.         if (hitInfo.hitSideOffset == lastHitOffset) continue;
  1247.         
  1248.         oldIsCaret = newIsCaret;
  1249.  
  1250.         /* save the old highlight and calculate the new one */
  1251.         lastHitOffset = (SelectionOffset) hitInfo.hitSideOffset;
  1252.         newIsCaret = (lastHitOffset == firstHitOffset);
  1253.         
  1254.         if (oldIsCaret || newIsCaret)
  1255.         {
  1256.             if (!oldIsCaret)
  1257.                 DrawHighlight(layout);
  1258.             if (!newIsCaret)
  1259.             {
  1260.                 NewSelectionAndHighlight(layout, firstHitOffset, lastHitOffset);
  1261.                 DrawHighlight(layout);
  1262.             }
  1263.         }
  1264.         else
  1265.         {
  1266.             oldHighlight = GXCopyToShape(oldHighlight, layout->highlight);
  1267.             NewSelectionAndHighlight(layout, firstHitOffset, lastHitOffset);
  1268.         
  1269.             /* to reduce flicker, draw the difference between the new and old highlight */
  1270.             diffHighlight = GXCopyToShape(diffHighlight, layout->highlight);
  1271.             GXExcludeShape(diffHighlight, oldHighlight);
  1272.             if (layout->highlightHideCount <= 0)
  1273.                 GXDrawShape(diffHighlight);
  1274.         }
  1275.     }
  1276.  
  1277.     if (newIsCaret)
  1278.     {
  1279.         ResetCaret(layout);
  1280.         NewSelectionAndHighlight(layout, firstHitOffset, lastHitOffset);
  1281.         DrawHighlight(layout);
  1282.     }
  1283.  
  1284.     UnlockEditHandle(handle);
  1285.  
  1286.     DisposeShapeAt(&diffHighlight);
  1287.     DisposeShapeAt(&oldHighlight);
  1288. }
  1289.  
  1290.  
  1291. void LayoutEditActivate(LayoutEditHandle handle)
  1292. {
  1293.     LayoutEditPtr layout = LockEditHandle(handle);
  1294.  
  1295.     if (layout->oldScript != GetEnvirons(smKeyScript))
  1296.         KeyScript(layout->oldScript);
  1297.         
  1298.     UpdateLayout(layout);
  1299.     ShowHighlight(layout);
  1300.     UnlockEditHandle(handle);
  1301. }
  1302.  
  1303.  
  1304. void LayoutEditDeactivate(LayoutEditHandle handle)
  1305. {
  1306.     LayoutEditPtr layout = LockEditHandle(handle);
  1307.  
  1308.     layout->oldScript = GetEnvirons(smKeyScript);
  1309.     
  1310.     HideHighlight(layout);
  1311.     UnlockEditHandle(handle);
  1312. }
  1313.  
  1314.  
  1315. void LayoutEditKey(LayoutEditHandle handle, char key)
  1316. {
  1317.     LayoutEditPtr layout = LockEditHandle(handle);
  1318.  
  1319.     switch (key)
  1320.     {
  1321.     case leftArrow:
  1322.     case rightArrow:
  1323.     {
  1324.         SelectionOffset newCaret; 
  1325.     
  1326.         HideHighlight(layout);
  1327.         UpdateLayout(layout);
  1328.         
  1329.         if (key == leftArrow)
  1330.             newCaret = GXGetLeftVisualOffset(
  1331.                 layout->layout,
  1332.                 layout->selectionRanges.ranges[0].minOffset);
  1333.         else newCaret = GXGetRightVisualOffset(
  1334.             layout->layout,
  1335.             layout->selectionRanges.ranges[0].maxOffset);
  1336.         
  1337.         NewSelection(layout, newCaret, newCaret);
  1338.         ResetCaret(layout);
  1339.         ShowHighlight(layout);
  1340.         break;
  1341.     }
  1342.     
  1343.     case backSpace:
  1344.     {
  1345.         DeleteSelection(layout);
  1346.         if (layout->nextUpdateTime == 0)
  1347.             layout->nextUpdateTime = TickCount() + nextUpdateDelta;
  1348.         break;
  1349.     }
  1350.     
  1351.     default:
  1352.     {
  1353.         switch (GetSelectionType(layout->selection))
  1354.         {
  1355.         case emptySelection:
  1356.             break;
  1357.         
  1358.         case discontiguousRange:
  1359.         case simpleRange:
  1360.             DeleteSelection(layout);
  1361.  
  1362.             /* fall through to simpleCaret case */
  1363.         
  1364.         case simpleCaret:
  1365.             InsertByte(layout, key);
  1366.             if (layout->nextUpdateTime == 0)
  1367.                 layout->nextUpdateTime = TickCount() + nextUpdateDelta;
  1368.         }
  1369.     }
  1370.     }
  1371.     
  1372.     UnlockEditHandle(handle);
  1373. }
  1374.  
  1375.  
  1376. void LayoutEditUpdate(LayoutEditHandle handle)
  1377. {
  1378.     LayoutEditPtr layout = LockEditHandle(handle);
  1379.  
  1380.     GXDrawShape(layout->layout);
  1381.  
  1382. #if BOUNDS    
  1383.     GXDrawShape(layout->bounds);
  1384. #endif
  1385.  
  1386.     DrawHighlight(layout);
  1387.     
  1388.     UnlockEditHandle(handle);
  1389. }
  1390.  
  1391.  
  1392. SelectionHandle LayoutEditGetSelection(LayoutEditHandle handle)
  1393. {
  1394.   LayoutEditPtr layout = (LayoutEditPtr) LockHandle(handle);
  1395.    SelectionHandle selection;
  1396.  
  1397.    UpdateLayout(layout);
  1398.    selection = layout->selection;
  1399.    UnlockEditHandle(handle);
  1400.  
  1401.    return selection;
  1402. }
  1403.  
  1404. void LayoutEditSetSelection(LayoutEditHandle handle, SelectionOffset start, SelectionOffset end)
  1405. {
  1406.     LayoutEditPtr layout = LockEditHandle(handle);
  1407.  
  1408.     UpdateLayout(layout);
  1409.     
  1410.     HideHighlight(layout);
  1411.     NewSelection(layout, start, end);
  1412.     ShowHighlight(layout);
  1413.     
  1414.     UnlockEditHandle(handle);
  1415. }
  1416.  
  1417. void LayoutEditSetSelectionHandle(LayoutEditHandle handle, SelectionHandle selection)
  1418. {
  1419.     SelectionOffset end, start;
  1420.  
  1421.     switch (GetSelectionType(selection))
  1422.     {
  1423.     case emptySelection:
  1424.     case discontiguousRange:
  1425.         return;
  1426.         
  1427.     case simpleCaret:
  1428.         start = end = GetCaretSelection(selection, nil);
  1429.         break;
  1430.     
  1431.     case simpleRange:
  1432.     {
  1433.         SelectionRanges ranges;
  1434.     
  1435.         (void) GetRangeSelection(selection, &ranges);
  1436.         start = ranges.ranges[0].minOffset;
  1437.         end = ranges.ranges[0].maxOffset;
  1438.         break;
  1439.     }
  1440.     }
  1441.     
  1442.     LayoutEditSetSelection(handle, start, end);
  1443. }
  1444.  
  1445. gxViewPort GetLayoutEditViewPort(LayoutEditHandle handle)
  1446. {
  1447.     LayoutEditPtr layout = LockEditHandle(handle);
  1448.     gxViewPort viewPort = GetShapeViewPort(layout->layout);
  1449.     
  1450.     UnlockEditHandle(handle);
  1451.     return viewPort;
  1452. }
  1453.  
  1454. void LayoutEditSetStyle(LayoutEditHandle handle, gxStyle newStyle)
  1455. {
  1456.     LayoutEditPtr layout = LockEditHandle(handle);
  1457.     SelectionType selectionType = GetSelectionType(layout->selection);
  1458.     
  1459.     UpdateLayout(layout);
  1460.     
  1461.     DisposeStyleAt(&layout->insertionStyle);
  1462.                     
  1463.     switch (selectionType)
  1464.     {
  1465.     case emptySelection:
  1466.     case discontiguousRange:
  1467.         /* should never happen */
  1468.         break;
  1469.         
  1470.     case simpleCaret:
  1471.         layout->insertionStyle = GXCloneStyle(newStyle);
  1472.         break;
  1473.         
  1474.     case simpleRange:
  1475.     {
  1476.         SelectionRanges *ranges = &layout->selectionRanges;
  1477.         SelectionOffset startOffset, endOffset;
  1478.         short length;
  1479.     
  1480.         SetEraser(layout);
  1481.         
  1482.         (void) GetRangeSelection(layout->selection, ranges);
  1483.         
  1484.         startOffset = ranges->ranges[0].minOffset;
  1485.         endOffset = ranges->ranges[0].maxOffset;
  1486.         length = endOffset - startOffset;
  1487.         
  1488.         GXSetLayoutParts(
  1489.             layout->layout,
  1490.             startOffset,
  1491.             endOffset,
  1492.             0,
  1493.             nil,
  1494.             nil,
  1495.             1,
  1496.             &length,
  1497.             &newStyle,
  1498.             0,
  1499.             nil,
  1500.             nil);
  1501.             
  1502.         DrawChangedLayout(layout);
  1503.  
  1504.         break;
  1505.     }
  1506.     }
  1507.  
  1508.     UnlockEditHandle(handle);
  1509. }
  1510.  
  1511. void LayoutEditIncrementLevel(LayoutEditHandle handle)
  1512. {
  1513.     LayoutEditPtr layout = LockEditHandle(handle);
  1514.  
  1515.     HideHighlight(layout);
  1516.     AdjustSelectedLevels(layout, 1);
  1517.     layout->flags |= highlightOutOfDate;
  1518.     ShowHighlight(layout);
  1519.     
  1520.     UnlockEditHandle(handle);
  1521. }
  1522.  
  1523. void LayoutEditDecrementLevel(LayoutEditHandle handle)
  1524. {
  1525.     LayoutEditPtr layout = LockEditHandle(handle);
  1526.  
  1527.     HideHighlight(layout);
  1528.     AdjustSelectedLevels(layout, -1);
  1529.     layout->flags |= highlightOutOfDate;
  1530.     ShowHighlight(layout);
  1531.     
  1532.     UnlockEditHandle(handle);
  1533. }
  1534.  
  1535. void LayoutEditSetLevel(LayoutEditHandle handle, long level)
  1536. {
  1537.     LayoutEditPtr layout = LockEditHandle(handle);
  1538.     SelectionType selectionType = GetSelectionType(layout->selection);
  1539.     short newLevel = level;
  1540.     
  1541.     UpdateLayout(layout);
  1542.     
  1543.     switch (selectionType)
  1544.     {
  1545.     case emptySelection:
  1546.     case discontiguousRange:
  1547.         /* should never happen */
  1548.         break;
  1549.         
  1550.     case simpleCaret:
  1551.         layout->insertionLevel = newLevel;
  1552.         break;
  1553.         
  1554.     case simpleRange:
  1555.     {
  1556.         SelectionRanges *ranges = &layout->selectionRanges;
  1557.         SelectionOffset startOffset, endOffset;
  1558.         short length;
  1559.     
  1560.         SetEraser(layout);
  1561.         
  1562.         (void) GetRangeSelection(layout->selection, ranges);
  1563.         
  1564.         startOffset = ranges->ranges[0].minOffset;
  1565.         endOffset = ranges->ranges[0].maxOffset;
  1566.         length = endOffset - startOffset;
  1567.         
  1568.         GXSetLayoutParts(
  1569.             layout->layout,
  1570.             startOffset,
  1571.             endOffset,
  1572.             0,
  1573.             nil,
  1574.             nil,
  1575.             0,
  1576.             nil,
  1577.             nil,
  1578.             1,
  1579.             &length,
  1580.             &newLevel);
  1581.  
  1582. #if BOUNDS            
  1583.         SetBounds(layout);
  1584. #endif
  1585.  
  1586.         HideHighlight(layout);
  1587.         DrawDifference(layout);
  1588.         layout->flags |= highlightOutOfDate;
  1589.         ShowHighlight(layout);
  1590.         
  1591.         layout->insertionLevel = -1;
  1592.         break;
  1593.     }
  1594.     }
  1595.  
  1596.     UnlockEditHandle(handle);
  1597. }
  1598.  
  1599. void LayoutEditCut(LayoutEditHandle handle)
  1600. {
  1601.     LayoutEditPtr layout = LockEditHandle(handle);
  1602.     SelectionType selectionType = GetSelectionType(layout->selection);
  1603.  
  1604.     if (selectionType != emptySelection && selectionType != simpleCaret)
  1605.     {
  1606.         CopySelection(layout);
  1607.         DeleteSelection(layout);
  1608.         HideHighlight(layout);
  1609.         UpdateLayout(layout);
  1610.         ShowHighlight(layout);
  1611.     }
  1612.     
  1613.     UnlockEditHandle(handle);
  1614. }
  1615.  
  1616. void LayoutEditCopy(LayoutEditHandle handle)
  1617. {
  1618.     LayoutEditPtr layout = LockEditHandle(handle);
  1619.  
  1620.     CopySelection(layout);
  1621.     
  1622.     UnlockEditHandle(handle);
  1623. }
  1624.  
  1625. void LayoutEditPaste(LayoutEditHandle handle)
  1626. {
  1627.     LayoutEditPtr layout = LockEditHandle(handle);
  1628.  
  1629.     HideHighlight(layout);
  1630.     PasteSelection(layout);
  1631.     ShowHighlight(layout);
  1632.     
  1633.     UnlockEditHandle(handle);
  1634. }
  1635.  
  1636. void LayoutEditClear(LayoutEditHandle handle)
  1637. {
  1638.     LayoutEditPtr layout = LockEditHandle(handle);
  1639.  
  1640.     DeleteSelection(layout);
  1641.     HideHighlight(layout);
  1642.     UpdateLayout(layout);
  1643.     ShowHighlight(layout);
  1644.     
  1645.     UnlockEditHandle(handle);
  1646. }
  1647.  
  1648. void LayoutEditFromScrap(LayoutEditHandle handle)
  1649. {
  1650.     LayoutEditPtr layout = LockEditHandle(handle);
  1651.     long offset, length;
  1652.     Handle buffer = NewHandle(0);
  1653.     
  1654.     if (GetScrap(buffer, 'FLAY', &offset) > 0)
  1655.     {
  1656.         long portCount = GXGetShapeViewPorts(GXGetDefaultShape(gxLayoutType), nil);
  1657.         gxViewPort *ports = (gxViewPort *) NewPtr(portCount * sizeof(gxViewPort));
  1658.     
  1659.         GXGetShapeViewPorts(GXGetDefaultShape(gxLayoutType), ports);
  1660.         DisposeShapeAt(&layout->scrap);
  1661.     
  1662.         layout->scrap = HandleToShape(buffer, portCount, ports);
  1663.         DisposePtr((Ptr) ports);
  1664.     }
  1665.     else if ((length = GetScrap(buffer, 'TEXT', &offset)) > 0)
  1666.     {
  1667.         void *text = (void *) LockHandle(buffer);
  1668.         short runLength = length;
  1669.         gxStyle defaultStyle = GXGetShapeStyle(layout->layout);
  1670.         short level0 = 0;
  1671.         
  1672.         DisposeShapeAt(&layout->scrap);
  1673.         layout->scrap = GXNewLayout(
  1674.             1,
  1675.             &runLength,
  1676.             (const void **) &text,
  1677.             1,
  1678.             &runLength,
  1679.             &defaultStyle,
  1680.             1,
  1681.             &runLength,
  1682.             &level0,
  1683.             nil,
  1684.             nil);
  1685.         
  1686.     }
  1687.     
  1688.     DisposeHandle(buffer);
  1689.     
  1690.     UnlockEditHandle(handle);
  1691. }
  1692.  
  1693. void LayoutEditToScrap(LayoutEditHandle handle)
  1694. {
  1695.     LayoutEditPtr layout = LockEditHandle(handle);
  1696.     
  1697.     ZeroScrap();
  1698.     
  1699.     if (layout->scrap)
  1700.     {
  1701.         long textLength;
  1702.         Ptr textPtr;
  1703.         Handle shapeHandle = ShapeToHandle(layout->scrap);
  1704.         
  1705.     
  1706.         textLength = GXGetLayout(layout->scrap, nil, nil, nil, nil, nil, nil, nil, nil, nil);
  1707.         textPtr = NewPtr(textLength);
  1708.         GXGetLayout(layout->scrap, (void *) textPtr, nil, nil, nil, nil, nil, nil, nil, nil);
  1709.         
  1710.         PutScrap(GetHandleSize(shapeHandle), 'FLAY', LockHandle(shapeHandle));
  1711.         PutScrap(textLength, 'TEXT', textPtr);
  1712.         
  1713.         DisposeShapeAt(&layout->scrap);
  1714.         DisposePtr(textPtr);
  1715.         DisposeHandle(shapeHandle);
  1716.     }
  1717.     
  1718.     UnlockEditHandle(handle);
  1719. }
  1720.  
  1721.  
  1722. void DisposeLayoutEditHandle(LayoutEditHandle handle)
  1723. {
  1724.     LayoutEditPtr layout = (LayoutEditPtr) LockHandle(handle);
  1725.  
  1726. #if BOUNDS
  1727.     DisposeShapeAt(&layout->bounds);
  1728.     DisposeShapeAt(&layout->boundsEraser);
  1729. #endif
  1730.     
  1731.     DisposeShapeAt(&layout->layout);
  1732.     DisposeShapeAt(&layout->eraser);
  1733.     DisposeShapeAt(&layout->highlight);
  1734.     DisposeShapeAt(&layout->scrap);
  1735.     DisposeStyleAt(&layout->insertionStyle);
  1736.     DisposeSelection(layout->selection);
  1737.     DisposeHandle(handle);
  1738. }
  1739.